package com.gopay.test.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.gopay.test.dao.BaseDAO;;

/**
 * 
 * @BaseDAO.java
 * @author
 * @2012-12-21 下午2:15:10 www.gopay.com.cn Inc.All rights reserved.
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public class BaseDAOImpl<T extends Serializable, Pk extends Serializable> implements BaseDAO<T, Pk> {

    @Resource(name = "hibernateTemplate")
    private HibernateTemplate hibernateTemplate;

    public HibernateTemplate getHibernateTemplate() {
        return hibernateTemplate;
    }

    public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
        this.hibernateTemplate = hibernateTemplate;
    }

    public T save(T entity) {
        getHibernateTemplate().save(entity);
        return entity;
    }

    public void delete(T entity) {
        getHibernateTemplate().delete(entity);
    }

    public void deleteAll(Collection<T> collection) {
        getHibernateTemplate().deleteAll(collection);
    }

    public List<T> findByExample(T entity) {
        return getHibernateTemplate().findByExample(entity);
    }

    public List<T> findAll(Class<T> entityClass) {
        return getHibernateTemplate().loadAll(entityClass);
    }

    public void update(T entity) {
        getHibernateTemplate().update(entity);
    }

    public T find(Class<T> entity, Pk id) {
        return (T) getHibernateTemplate().get(entity, id);
    }

    public List<T> findByCriteria(DetachedCriteria criteria) {
        return getHibernateTemplate().findByCriteria(criteria);
    }

    public List<T> findBySql(final String sql) {
        return findBySql(sql, null);
    }

    public List<T> findBySqlScalar(final String sql, final Set<String> scalarSet) {
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                SQLQuery query = session.createSQLQuery(sql);
                for (String scalar : scalarSet) {
                    query.addScalar(scalar);
                }
                List<T> list = query.list();
                return list;
            }
        });
    }

    public List<T> findBySql(final String sql, final Map<String, Object> param) {
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createSQLQuery(sql);
                if (param != null) {
                    Iterator<String> it = param.keySet().iterator();
                    while (it.hasNext()) {
                        String key = it.next();
                        Object value = param.get(key);
                        if (value instanceof Object[]) {
                            query.setParameterList(key, (Object[]) value);
                        } else {
                            query.setString(key, param.get(key).toString());
                        }
                    }
                }
                return query.list();
            }
        });
    }

    public int findCountBySql(final String sql, final Map<String, Object> param) {
        return (Integer) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createSQLQuery(sql);
                if (param != null) {
                    Iterator<String> it = param.keySet().iterator();
                    while (it.hasNext()) {
                        String key = it.next();
                        Object value = param.get(key);
                        if (value instanceof Object[]) {
                            query.setParameterList(key, (Object[]) value);
                        } else {
                            query.setString(key, param.get(key).toString());
                        }
                    }
                }
                List<T> list = query.list();
                return Integer.parseInt(list.get(0).toString());
            }
        });
    }

    public List<T> findByHql(final String hql) {
        return findByHql(hql, null);
    }

    public List<T> findByHql(final String hql, final Map<String, Object> param) {
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                if (param != null) {
                    Iterator<String> it = param.keySet().iterator();
                    while (it.hasNext()) {
                        String key = it.next();
                        Object value = param.get(key);
                        if (value instanceof Object[]) {
                            query.setParameterList(key, (Collection<T>) value);
                        } else {
                            query.setString(key, param.get(key).toString());
                        }
                    }
                }
                return query.list();
            }
        });
    }

    public List<T> findByHql(final String hql, final Map<String, Object> param, final int pageIndex, final int pageSize) {
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                if (param != null) {
                    Iterator<String> it = param.keySet().iterator();
                    while (it.hasNext()) {
                        String key = it.next();
                        Object value = param.get(key);
                        if (value instanceof Object[]) {
                            query.setParameterList(key, (Collection<T>) value);
                        } else if (value instanceof Date) {
                            query.setDate(key, (Date) param.get(key));
                        } else {
                            query.setString(key, param.get(key).toString());
                        }
                    }
                }
                if (pageIndex >= 1) {
                    query.setFirstResult((pageIndex - 1) * pageSize);
                    query.setMaxResults(pageSize);
                }
                return query.list();
            }
        });
    }

    public int findCountByHql(final String hql, final Map<String, Object> param) {
        return (Integer) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                if (param != null) {
                    Iterator<String> it = param.keySet().iterator();
                    while (it.hasNext()) {
                        String key = it.next();
                        Object value = param.get(key);
                        if (value instanceof Object[]) {
                            query.setParameterList(key, (Collection<T>) value);
                        } else if (value instanceof Date) {
                            query.setDate(key, (Date) param.get(key));
                        } else {
                            query.setString(key, param.get(key).toString());
                        }
                    }
                }
                return Integer.parseInt(query.list().get(0).toString());
            }
        });
    }

    public List<T> findByCriteria(final DetachedCriteria criteria, final int pageNo, final int pageSize) {
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Criteria c = criteria.getExecutableCriteria(session);
                if (pageNo >= 1) {
                    return c.setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();
                }
                return c.list();
            }
        });
    }

    public int findCountByCriteria(final DetachedCriteria criteria) {
        return (Integer) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Criteria c = criteria.getExecutableCriteria(session);
                return c.setProjection(Projections.rowCount()).uniqueResult();
            }
        });
    }

    public List<T> findBySql(final String sql, final int pageNo, final int pageSize) {
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createSQLQuery(sql);
                if (pageNo >= 1) {
                    query.setFirstResult((pageNo - 1) * pageSize);
                    query.setMaxResults(pageSize);
                }
                List<T> list = query.list();
                return list;
            }
        });
    }

    public List<T> findBySql(final String sql, final Map<String, Object> param, final int pageNo, final int pageSize) {
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createSQLQuery(sql);
                if (param != null) {
                    Iterator<String> it = param.keySet().iterator();
                    while (it.hasNext()) {
                        String key = it.next();
                        Object value = param.get(key);
                        if (value instanceof Object[]) {
                            query.setParameterList(key, (Collection<T>) value);
                        } else {
                            query.setString(key, param.get(key).toString());
                        }
                    }
                }
                if (pageNo >= 1) {
                    query.setFirstResult((pageNo - 1) * pageSize);
                    query.setMaxResults(pageSize);
                }
                List<T> list = query.list();
                return list;
            }
        });
    }

    public List<T> findBySqlScalar(final String sql, final int pageNo, final int pageSize, final Set<String> scalarSet) {
        return (List<T>) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                SQLQuery query = session.createSQLQuery(sql);
                for (String scalar : scalarSet) {
                    query.addScalar(scalar);
                }
                if (pageNo >= 1) {
                    query.setFirstResult((pageNo - 1) * pageSize);
                    query.setMaxResults(pageSize);
                }
                List<T> list = query.list();
                return list;
            }
        });
    }

    public int findCountBySql(final String sql) {
        return (Integer) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createSQLQuery(sql);
                List<T> list = query.list();
                return Integer.parseInt(list.get(0).toString());
            }
        });
    }

    public int deleteByHql(final String hql) {
        return (Integer) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                return query.executeUpdate();
            }
        });
    }

    public int updateByHql(final String hql) {
        return (Integer) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(hql);
                return query.executeUpdate();
            }
        });
    }

    public String getNextId(final String sequence) {
        List<Object> data = this.getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
            @Override
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                return session.createSQLQuery("select " + sequence + ".nextval from dual").list();
            }
        });
        return data.get(0).toString();
    }

    public int bulkUpdate(String queryString) {
        return getHibernateTemplate().bulkUpdate(queryString);
    }

    public int bulkUpdate(String queryString, Object[] values) {
        return getHibernateTemplate().bulkUpdate(queryString, values);
    }

}
